//////////////////////////////////////////////
/// CALCULADORA PARA CEGOS
/// 
/// Gestão de Projecto de Software 2013-2014
///
/// Grupo 14:
/// Diogo Moita - 21170937
/// Diogo Oliveira - 21180842
/// Luís Monteiro - 21170270
/// Luís Costa - 21210392
/// Nuno Aguiar - 21160515
/// Pedro Marques - 21160524
//////////////////////////////////////////////
package cvi;

import com.sun.speech.freetts.*; // http://freetts.sourceforge.net/docs/index.php
import java.text.DecimalFormat;

public class Voz {

    public final static float VOZ_NORMAL = (float) 1.0;
    public final static float VOZ_RAPIDA = (float) 0.7;
    public final static String AVISO = "NO!";
    public final static String ERRO = "ERROR!!";

    private final String nome;
    private static Voice voice;
    private static boolean talking;

    public Voz(String nome) {
        this.nome = nome; // Atribuir o nome à voz
        voice = VoiceManager.getInstance().getVoice(this.nome); // Atribuir a voz ao sistema de voz
        voice.allocate(); // Carrega o lexicon e o handler para a saida de audio
        voice.setRate(150); // Velocidade entre palavras. (150 = normal)
        voice.setPitch(100); // Pitch da voz. (100 = normal)
        voice.setDurationStretch(VOZ_NORMAL); // Velocidade da voz (1.0 = normal)
        voice.speak("Welcome!");
        System.out.println("Voz online.");
    }

    // "Diz" várias frases.
    // texto: array de strings com texto para ser dito.
    public void diz(final String[] texto) {
        //voice.getOutputQueue().removeAll();
        voice.getAudioPlayer().cancel();
        voice.setDurationStretch(VOZ_NORMAL);
        talking = true;
        new Thread() {
            @Override
            public void run() {
                for (String frase : texto) {
                    if (frase.isEmpty()) {
                        break;
                    }
                    System.out.println("Voz: " + frase);
                    voice.speak(frase);
                }
                talking = false;
            }
        }.start();
    }

    // "Diz" uma frase.
    // texto: string que contem a frase a ser dita.
    public void diz(final String frase) {
        if (frase.isEmpty() || talking == true) {
            return;
        }
        //voice.getOutputQueue().removeAll();
        voice.getAudioPlayer().cancel();
        voice.setDurationStretch(VOZ_RAPIDA);
        new Thread() {
            @Override
            public void run() {
                System.out.println("Voz: " + frase);
                voice.speak(frase);
            }
        }.start();
    }

    // Altera a velocidade com que a voz "fala".
    // velocidade: valor da velocidade
    public void setVelocidade(float velocidade) {
        if (velocidade <= 0.0) { // Isto nunca deverá acontecer mas nunca se sabe
            return;
        }
        voice.setDurationStretch(velocidade);
    }

    // Processa a operação e "diz" a uma velocidade mais lenta
    // valor1: primeiro valor da operação.
    // operador: operador da operação
    // valor2: segundo valor da operação.
    // resultado: resultado da operação.
    public void processaEdiz(double valor1, char operador, double valor2, double resultado, boolean perc) {

        String[] processado = new String[4]; // Array de strings onde vai ficar armazenado o que será "dito".

        processado[0] = d2s(valor1);

        switch (operador) {
            case '+':
                processado[1] = "plus";
                break;
            case '-':
                processado[1] = "minus";
                break;
            case '*':
                processado[1] = "times";
                break;
            case '/':
                processado[1] = "divide by";
                break;
        }

        processado[2] = d2s(valor2);
        if (!perc) // Se calculo normal
        {
            processado[3] = "equals to " + d2s(resultado);
        } else // Se calculo com percentagem
        {
            processado[3] = "percent, equals to " + d2s(resultado);
        }

        voice.setDurationStretch(VOZ_NORMAL);
        this.diz(processado);
    }

    // Processa a operação e "diz" a uma velcidade mais lenta
    // operador: operador da operação
    // valor: valor da operação.
    // resultado: resultado da operação.
    public void processaEdiz(char operador, double valor, double resultado) {
        String[] processado = new String[3]; // Array de strings onde vai ficar armazenado o que será "dito".

        switch (operador) {
            case 'R': // raiz quadrada
                processado[0] = "square root of";
                break;
            case 'Q': // valor ao quadrado
                processado[0] = "square of";
                break;
        }

        processado[1] = d2s(valor);
        processado[2] = "equals to " + d2s(resultado);

        voice.setDurationStretch(VOZ_NORMAL);
        this.diz(processado);
    }

    /*
     // Diz o numero recebido em formato string
     // s: string com o valor a ser dito
     public void dizNumero(String s) {
     String[] d_dividido = s.split("."); // dividir valor pelo ponto.
     if (d_dividido.length == 2) { // =2 significa que tem parte decimal. Tem de ser tratada.
     if (d_dividido[1].startsWith("0")) {
     d_dividido[1] = d_dividido[1].replace("0", "0 "); // substituir 0 por 0+espaço para forçar a voz a dizer os zeros na parte decimal.
     }
     String juntar = new StringBuilder(d_dividido[0]).append(" point ").append(d_dividido[1]).toString(); // juntar parte inteira, decimal e o ponto.
     diz(juntar);
     } else {
     diz(d_dividido[0]);
     }
     }
     */
    // Converte um valor double para string num formato mais indicado para ser "dito".
    // d: valor double a converter para string
    String d2s(double d) {
        DecimalFormat df = new DecimalFormat("#.########"); // Necessario para formatar corretamente valores double para string.
        String d_string = df.format(d); // converter d para string
        String[] d_dividido = d_string.split(","); // dividir valor pela virgula.
        d_dividido[0].replace("-", "minus ");
        if (d_dividido.length == 2) { // =2 significa que tem parte decimal. Tem de ser tratada.
            if (d_dividido[1].startsWith("0")) {
                // Contar zeros depois do ponto         
                String zeros = "";
                int i = 0;
                for (i = 0; i < d_dividido[1].length(); i++) {
                    if (d_dividido[1].charAt(i) != '0') {
                        break;
                    }
                    zeros += "0";
                }
                zeros = zeros.replace("0", "0 "); // substituir 0 por 0+espaço para forçar a voz a dizer os zeros na parte decimal.
                d_dividido[1] = zeros + d_dividido[1].substring(i); // juntar zeros com espaço com o resto.
            }
            String juntar = new StringBuilder(d_dividido[0]).append(" point ").append(d_dividido[1]).toString(); // juntar parte inteira, decimal e o ponto.
            return juntar;
        } else {
            return d_dividido[0];
        }
    }

    // (debug) Imprimi na consola todas os tipos de vozes disponveis.
    public void listarTipoVozes() {
        VoiceManager vm = VoiceManager.getInstance();
        System.out.println(vm.getVoiceInfo());
    }

    // Desativa o processamento de voz.
    public void desativar() {
        voice.getOutputQueue().removeAll();
        voice.getAudioPlayer().cancel();
        setVelocidade(VOZ_NORMAL);
        voice.speak("Goodbye!");
        voice.deallocate();
    }
}
